package com.hh.flow.service.impl;

import com.hh.flow.service.DefService;
import com.monkey.flow.core.webService.DefAppService;
import com.monkey.flow.core.webService.NodeAppService;
import com.monkey.flow.core.webService.SkipAppService;
import com.monkey.flow.core.constant.FlowConstant;
import com.monkey.flow.core.domain.entity.FlowDefinition;
import com.monkey.flow.core.domain.entity.FlowNode;
import com.monkey.flow.core.domain.entity.FlowSkip;
import com.monkey.flow.core.enums.ApprovalAction;
import com.monkey.flow.core.enums.NodeType;
import com.monkey.flow.core.utils.AssertUtil;
import com.monkey.tools.utils.CollUtil;
import com.monkey.tools.utils.ObjectUtil;
import com.monkey.tools.utils.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @description:  流程定义serviceImpl
 * @author minliuhua
 * @date: 2023/5/29 13:09
 */
@Service
public class DefServiceImpl implements DefService {

    @Resource
    private DefAppService defAppService;

    @Resource
    private NodeAppService nodeAppService;

    @Resource
    private SkipAppService skipAppService;
    @Override
    public List<FlowNode> getNodeList(Long definitionId)
    {
        FlowNode flowNode = new FlowNode();
        flowNode.setDefinitionId(definitionId);
        List<FlowNode> flowNodes = nodeAppService.getService().list(flowNode);
        StringBuffer skipDescribe;
        Map<String, String> nodeMap = flowNodes.stream().collect(Collectors.toMap(FlowNode::getNodeCode, FlowNode::getNodeName));
        for (FlowNode node : flowNodes) {
            skipDescribe = new StringBuffer();
            FlowSkip skip = new FlowSkip();
            skip.setNodeId(node.getId());
            List<FlowSkip> skips = skipAppService.getService().list(skip);
            for (FlowSkip flowSkip : skips) {
                if(StringUtils.isNotEmpty(ApprovalAction.getValueByKey(flowSkip.getConditionValue()))){
                    skipDescribe.append("【").append(ApprovalAction.getValueByKey(flowSkip.getConditionValue()))
                            .append("】");
                }
                skipDescribe.append("流转到").append("【")
                        .append(nodeMap.get(flowSkip.getNextNodeCode())).append("】;  ");
            }
            if (StringUtils.isEmpty(skipDescribe.toString())) {
                node.setSkipDescribe("无");
            } else {
                node.setSkipDescribe(skipDescribe.toString());
            }
        }
        return flowNodes;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveNode(List<FlowNode> flowNodeList, Long definitionId)
    {
        List<Integer> nodeTypes = flowNodeList.stream().map(FlowNode::getNodeType).collect(Collectors.toList());
        AssertUtil.isTrue(nodeTypes.contains(NodeType.START.getKey())
                && nodeTypes.contains(NodeType.END.getKey()), "必须有开始结点和结束结点");

        // 校验每一个流程的开始结点个数
        int startNum = 0;
        for (FlowNode flowNode : flowNodeList) {
            AssertUtil.isTrue(StringUtils.isAllNotEmpty(flowNode.getNodeCode(), flowNode.getNodeName()), "结点编码和结点名称不能为空");
            AssertUtil.isFalse(ObjectUtil.isNull(flowNode.getNodeType()), "结点类型不能为空");
            if (NodeType.START.getKey().equals(flowNode.getNodeType())) {
                startNum++;
                AssertUtil.isFalse(startNum > 1, FlowConstant.MUL_START_NODE);
            }
        }

        FlowNode nodeQuery = new FlowNode();
        nodeQuery.setDefinitionId(definitionId);
        // 获取原始结点
        List<FlowNode> flowNodesOrig = nodeAppService.getService().list(nodeQuery);

        Set<Long> origNodeIds = flowNodesOrig.stream().map(FlowNode::getId).collect(Collectors.toSet());
        Set<Long> tarNodeIds = flowNodeList.stream().map(FlowNode::getId).collect(Collectors.toSet());

        // 新增结点
        List<FlowNode> nodesAdd = new ArrayList<>();
        // 更新结点
        List<FlowNode> nodesUpdate = new ArrayList<>();
        for (FlowNode flowNode : flowNodeList) {
            if (ObjectUtil.isNull(flowNode.getId())) {
                nodesAdd.add(flowNode);
            } else if (origNodeIds.contains(flowNode.getId())) {
                nodesUpdate.add(flowNode);
            }
        }

        // 删除结点
        List<Long> nodesDelete = new ArrayList<>();
        for (Long origNodeId : origNodeIds) {
            if (!tarNodeIds.contains(origNodeId))
            {
                nodesDelete.add(origNodeId);
            }
        }

        //  执行新增
        FlowDefinition flowDefinition = defAppService.getService().getById(definitionId);
        for (FlowNode flowNode : nodesAdd) {
            flowNode.setDefinitionId(definitionId);
            flowNode.setVersion(flowDefinition.getVersion());
        }

        if (CollUtil.isNotEmpty(nodesAdd)) {
            nodeAppService.getService().saveBatch(nodesAdd);
        }

        // 执行更新
        if (CollUtil.isNotEmpty(nodesUpdate)) {
            nodeAppService.getService().updateBatch(nodesUpdate);
        }

        // 执行删除
        if (CollUtil.isNotEmpty(nodesDelete)) {
            skipAppService.getService().deleteByNodeIds(nodesDelete);
            nodeAppService.getService().removeByIds(nodesDelete);
        }
    }

    /**
     * 保存流程跳转
     * @param skipList
     * @param nodeId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveSkip(List<FlowSkip> skipList, Long nodeId)
    {
        // 校验
        for (FlowSkip flowSkip : skipList) {
            AssertUtil.isTrue(StringUtils.isAllNotEmpty(flowSkip.getNextNodeCode(), flowSkip.getConditionValue())
                    , "下一个流程结点编码和跳转不能为空");
        }

        FlowNode node = nodeAppService.getService().getById(nodeId);
        if (!NodeType.END.getKey().equals(node.getNodeType())) {
            AssertUtil.isFalse(CollectionUtils.isEmpty(skipList), "开始和中间结点必须有跳转规则");
        }
        //跳转条件的集合
        Set<String> conditionSet = new HashSet<>();
        //目标结点的集合 这两个集合都不能重复
        Set<String> targetSet = new HashSet<>();
        //遍历结点下的跳转条件
        for (int i = 0; i < skipList.size(); i++) {
            FlowSkip skip = skipList.get(i);
            //目标结点
            String target = skip.getNextNodeCode();
            AssertUtil.isBlank(target, FlowConstant.LOST_DEST_NODE);
            AssertUtil.isFalse(targetSet.contains(target), FlowConstant.SAME_DEST_NODE);
            targetSet.add(target);
            String value = skip.getConditionValue();
            AssertUtil.isFalse(conditionSet.contains(value), FlowConstant.SAME_CONDITION_VALUE);
            conditionSet.add(value);

            skip.setNodeId(node.getId());
            skip.setDefinitionId(node.getDefinitionId());
            skip.setNowNodeCode(node.getNodeCode());
        }
        skipAppService.getService().deleteByNodeId(nodeId);
        skipAppService.getService().saveBatch(skipList);
    }

}
